/*
 * Copyright (c) 2007 jNetX.
 * http://www.jnetx.com
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * jNetX. You shall not disclose such Confidential Information and
 * shall use it only in accordance with the terms of the license
 * agreement you entered into with jNetX.
 *
 * $Id$
 */
package com.jnetx.javax.sip;

import com.jnetx.javax.sip.header.CallIdHeaderImpl;
import com.jnetx.javax.sip.util.CallIdGenerator;
import com.jnetx.javax.sip.util.SequentialCallIdGenerator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.sip.*;
import javax.sip.header.CallIdHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.util.*;

/**
 * @author <a href="mailto:dparhonin@jnetx.ru">Dmitry Parhonin</a>
 * @version $Revision$
 */
public class SipProviderImpl implements SipProvider {
    private final static Log logger = LogFactory.getLog(SipProviderImpl.class);

    private final SipStack sipStack;
    private List<SipListener> listeners = new ArrayList<SipListener>();
    private Map<String, ListeningPoint> listeningPoints = new HashMap<String, ListeningPoint>();

    private CallIdGenerator callIdGenerator = SequentialCallIdGenerator.getInstance();

    public SipProviderImpl(SipStack sipStack) {
        this.sipStack = sipStack;
    }

    public void addSipListener(SipListener sipListener) throws TooManyListenersException {
        if (logger.isDebugEnabled()) logger.debug("addSipListener(sipListener=" + sipListener + ")");
        listeners.add(sipListener);
    }

    public void removeSipListener(SipListener sipListener) {
        if (logger.isDebugEnabled()) logger.debug("removeSipListener(sipListener=" + sipListener + ")");
        listeners.remove(sipListener);
    }

    public SipStack getSipStack() {
        return sipStack;
    }

    /**
     * @deprecated
     */
    public ListeningPoint getListeningPoint() {
        if (listeningPoints.size() != 0)
            return listeningPoints.get(0);
        else
            return null;
    }

    public ListeningPoint[] getListeningPoints() {
        return listeningPoints.values().toArray(new ListeningPoint[listeningPoints.size()]);
    }

    /**
     * @deprecated
     */
    public void setListeningPoint(ListeningPoint listeningPoint) throws ObjectInUseException {
        if (logger.isDebugEnabled()) logger.debug("setListeningPoint(listeningPoint=" + listeningPoint + ")");
        listeningPoints.clear();
        listeningPoints.put(listeningPoint.getTransport(), listeningPoint);
    }

    public void addListeningPoint(ListeningPoint listeningPoint) throws ObjectInUseException, TransportAlreadySupportedException {
        if (logger.isDebugEnabled()) logger.debug("addListeningPoint(listeningPoint=" + listeningPoint + ")");
        final String transport = listeningPoint.getTransport();
        if (listeningPoints.containsKey(transport))
            throw new TransportAlreadySupportedException("There is a registered listener already for transport " + transport);
        listeningPoints.put(listeningPoint.getTransport(), listeningPoint);
    }

    public ListeningPoint getListeningPoint(String transport) {
        return listeningPoints.get(transport);
    }

    public void removeListeningPoint(ListeningPoint listeningPoint) throws ObjectInUseException {
        if (logger.isDebugEnabled()) logger.debug("removeListeningPoint(listeningPoint=" + listeningPoint + ")");
        listeningPoints.remove(listeningPoint.getTransport());
    }

    private final static String localHost;

    static {
        String address = null;
        try {
            address = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            logger.error("Cannot get the local host's IP address!", e);
        } finally {
            localHost = address;
        }
    }

    /**
     * {@inheritDoc}
     */
    public CallIdHeader getNewCallId() {
        final StringBuilder sb = new StringBuilder(callIdGenerator.getLocalUID());
        sb.append('@').append(localHost);
        final CallIdHeader header = new CallIdHeaderImpl();
        try {
            header.setCallId(sb.toString());
        } catch (ParseException e) {
            logger.error("Cannot set CallId value!", e);
        }
        return header;
    }

    public ClientTransaction getNewClientTransaction(Request request) throws TransactionUnavailableException {
        return new ClientTransactionImpl(request, this);
    }

    public ServerTransaction getNewServerTransaction(Request request) throws TransactionAlreadyExistsException, TransactionUnavailableException {
        return new ServerTransactionImpl(request, this);
    }

    public void sendRequest(Request request) throws SipException {
        //todo Implement this
    }

    public void sendResponse(Response response) throws SipException {
        //todo Implement this
    }

    public Dialog getNewDialog(Transaction transaction) throws SipException {
        //todo Implement this
        return null;
    }

    public void setAutomaticDialogSupportEnabled(boolean b) {
        //todo Implement this
    }
}
/*
 * $Log$
 */